#!/usr/bin/pytho

'''
Chris Stabb's roguelike lololololo
'''

#############################################
# imports
#############################################

import os
import random
import libtcodpy as libtcod

#############################################
# utility functions
#############################################

def getKey(key):
    '''Returns key press'''
    if key.vk == libtcod.KEY_CHAR:
        return chr(key.c)
    else:
        return key.vk

#############################################
# game functions
#############################################

def updateUI(update_this, with_this):
    """Update the various UI elements separately"""
    global fov_py, fov_px, fov_recompute, smap, messages
    global p_name, p_lvl, p_race, p_hp, p_max_hp, p_max_str, p_debt_str
    global p_max_dex, p_debt_dex, p_max_tec, p_debt_tec, p_max_knl, p_debt_knl

    libtcod.console_set_foreground_color(0, libtcod.white)

    if update_this == 'player position' :
        dx, dy = movement_keys[with_this]
        if smap[fov_py+dy][fov_px+dx] == ' ':
            libtcod.console_put_char(0, fov_px+view_diff_width, fov_py, ' ', libtcod.BKGND_NONE)
            fov_px = fov_px + dx
            fov_py = fov_py + dy
            libtcod.console_put_char(0, fov_px+view_diff_width, fov_py, '@',
                                                 libtcod.BKGND_NONE)
            fov_recompute = True
    elif update_this == 'player name' :
        p_name = with_this
        libtcod.console_print_left(0, 1, 1, libtcod.BKGND_NONE, str(p_name))
    elif update_this == 'player race' :
        p_race = with_this
        libtcod.console_print_left(0, 1, 2, libtcod.BKGND_NONE, str(p_race))
    elif update_this == 'player level' :
        p_lvl = with_this
        libtcod.console_print_left(0, 8, 3, libtcod.BKGND_NONE, str(p_lvl))
    elif update_this == 'player hp' :
        p_hp = with_this
        libtcod.console_print_left(0, 1, 4, libtcod.BKGND_NONE, 'HP     ' + str(p_hp) + ' / ' + str(p_max_hp))
    elif update_this == 'player max hp' :
        p_max_hp = with_this
        libtcod.console_print_left(0, 1, 4, libtcod.BKGND_NONE, 'HP     ' + str(p_hp) + ' / ' + str(p_max_hp))
    elif update_this == 'player status' :
        p_status = with_this
        libtcod.console_print_left(0, 1, 5, libtcod.BKGND_NONE, 'Status ')
        libtcod.console_set_foreground_color(0, libtcod.green)
        libtcod.console_print_left(0, 8, 5, libtcod.BKGND_NONE, str(p_hp))
    elif update_this == 'player max str' :
        p_max_str = with_this
        libtcod.console_print_left(0, 1, 7, libtcod.BKGND_NONE, 'STR ' + str_curr_str + ' (' + str(p_max_str) + ' - ' + str(p_debt_str))
    elif update_this == 'player debt str' :
        p_debt_str = with_this
        libtcod.console_print_left(0, 1, 7, libtcod.BKGND_NONE, 'STR ' + str_curr_str + ' (' + str(p_max_str) + ' - ' + str(p_debt_str))
    elif update_this == 'player max dex' :
        p_max_dex = with_this
        libtcod.console_print_left(0, 1, 8, libtcod.BKGND_NONE, 'DEX ' + str_curr_dex + ' (' + str(p_max_dex) + ' - ' + str(p_debt_dex))
    elif update_this == 'player debt dex' :
        p_debt_dex = with_this
        libtcod.console_print_left(0, 1, 8, libtcod.BKGND_NONE, 'DEX ' + str_curr_dex + ' (' + str(p_max_dex) + ' - ' + str(p_debt_dex))
    elif update_this == 'player max tec' :
        p_max_tec = with_this
        libtcod.console_print_left(0, 1, 9, libtcod.BKGND_NONE, 'TEC ' + str_curr_tec + ' (' + str(p_max_tec) + ' - ' + str(p_debt_tec))
    elif update_this == 'player debt tec' :
        p_debt_tec = with_this
        libtcod.console_print_left(0, 1, 9, libtcod.BKGND_NONE, 'TEC ' + str_curr_tec + ' (' + str(p_max_tec) + ' - ' + str(p_debt_tec))
    elif update_this == 'player max knl' :
        p_max_knl = with_this
        libtcod.console_print_left(0, 1, 7, libtcod.BKGND_NONE, 'KNL ' + str_curr_knl + ' (' + str(p_max_knl) + ' - ' + str(p_debt_knl))
    elif update_this == 'player debt knl' :
        p_debt_knl = with_this
        libtcod.console_print_left(0, 1, 7, libtcod.BKGND_NONE, 'KNL ' + str_curr_knl + ' (' + str(p_max_knl) + ' - ' + str(p_debt_knl))
    elif update_this == 'messages' :
        print_messages = []
        messages.append(with_this)

        # messages must be bound to 100 message limit
        if len(messages) > 100 :
            del messages[0]

        # clear message window
        for y in range(0, messages_height) :
            libtcod.console_print_left(0, view_diff_width, y + map_height, libtcod.BKGND_NONE, '                                                           ')

        #construct messages to print to the console
        for i in range(len(messages), 0, -1) :
            one_message = []
            mod = len(messages[i-1]) / (messages_width - 2)
            if mod > 0 :
                while mod >= 0 :
                    one_message.append(messages[i-1][mod*(messages_width - 2):(mod+1)*(messages_width - 2)])
                    one_message.reverse()
                    mod -= 1
            else :
                one_message.append(messages[i-1])
            for j in range(len(one_message)) :
                print_messages.append(one_message[j])
            del one_message

        # print messages to message window
        for y in range(0, (messages_height - 2)) :
            if y < len(print_messages) :
                libtcod.console_print_left(0, view_diff_width + 1, map_height + 1 + y, libtcod.BKGND_NONE, str(print_messages[y]))
        del print_messages

def changeEnvironment(enviro) :
    '''set the environment colors'''
    global fov_colors, environments, current_environment

    if enviro=='none' :
        if current_environment == len(environments):
            current_environment = 0
        enviro=environments[current_environment]
        current_environment = current_environment+1

    if enviro=='swamp' :
        fov_colors['dark wall'] = libtcod.Color(0,100,0)
        fov_colors['light wall'] = libtcod.Color(130,110,50)
        fov_colors['dark ground'] = libtcod.Color(50,150,50)
        fov_colors['light ground'] = libtcod.Color(200,180,50)
    elif enviro=='desert' :
        fov_colors['dark wall'] = libtcod.Color(0,100,100)
        fov_colors['light wall'] = libtcod.Color(130,110,50)
        fov_colors['dark ground'] = libtcod.Color(50,150,150)
        fov_colors['light ground'] = libtcod.Color(200,180,50)
    elif enviro=='cave' :
        fov_colors['dark wall'] = libtcod.Color(100,0,0)
        fov_colors['light wall'] = libtcod.Color(130,110,50)
        fov_colors['dark ground'] = libtcod.Color(150,50,50)
        fov_colors['light ground'] = libtcod.Color(200,180,50)
    elif enviro=='ship' :
        fov_colors['dark wall'] = libtcod.Color(0,0,100)
        fov_colors['light wall'] = libtcod.Color(130,110,50)
        fov_colors['dark ground'] = libtcod.Color(50,50,150)
        fov_colors['light ground'] = libtcod.Color(200,180,50)
    else:
        fov_colors['dark wall'] = libtcod.Color(0,0,100)
        fov_colors['light wall'] = libtcod.Color(130,110,50)
        fov_colors['dark ground'] = libtcod.Color(50,50,150)
        fov_colors['light ground'] = libtcod.Color(200,180,50)

    
    libtcod.console_print_left(0, 10, 1, libtcod.BKGND_NONE, enviro)

def generateRandomMap() :
    """Generates a random map for play."""
    """Will eventually be merged with generic map generation class."""
    global smap
    s = ''

    del smap[:]

    for y in range(map_height) :
        #print 'y =',y,'and s =',s
        s = ''
        for x in range(map_width) :
            bit = random.randint(0,1)
            if bit == 0 :
                s = s + ('#')
            else :
                s = s + (' ')
        smap.append(s)
    #print smap


#############################################
# global constants and variables
#############################################

# size variables - old 64x40 - moving to 80x50
window_width = 80
window_height = 50
map_width = 60
map_height = 35
view_diff_width = window_width - map_width
view_diff_height = window_height - map_height
messages_width = map_width
messages_height = window_height - map_height

# fov variables
first = True
fov_px = 9
fov_py = 10
fov_recompute = True
fov_map = None
fov_colors =    {
                'dark wall' : libtcod.Color(0, 0, 100),
                'light wall' : libtcod.Color(130, 110, 50),
                'dark ground' : libtcod.Color(50, 50, 150),
                'light ground' : libtcod.Color(200, 180, 50)
                }
fov_init = False
fov_radius = 5

# player variables
p_name = 'Shepard'
p_max_hp = 1
p_curr_hp = 1
p_lvl = 1
p_max_str = 10   # strength
p_max_dex = 10   # dexterity
p_max_tec = 10   # technical aptitude
p_max_knl = 10   # knowledge
p_debt_str = 1
p_debt_dex = 3
p_debt_tec = 2
p_debt_knl = 6
p_curr_str = p_max_str - p_debt_str
p_curr_dex = p_max_dex - p_debt_dex
p_curr_tec = p_max_tec - p_debt_tec
p_curr_knl = p_max_knl - p_debt_knl
p_race = 'Human'
p_status = 'Healthy'

# environment variables
environments =  {
                0   : 'swamp',
                1   : 'desert',
                2   : 'cave',
                3   : 'ship'
                }
current_environment = 0

# message variables
messages = []

# movement key variables
do =    {
        'up'        : (0, -1),
        'down'      : (0, 1),
        'right'     : (1, 0),
        'left'      : (-1, 0),
        'upleft'    : (-1, -1),
        'upright'   : (1, -1),
        'downleft'  : (-1, 1),
        'downright' : (1, 1),
        'wait'      : (0, 0)
        }
movement_keys =  {
        'i'                 : do['up'],
        'k'                 : do['down'],
        'j'                 : do['left'],
        'l'                 : do['right'],
        #libtcod.KEY_UP      : do['up'],
        libtcod.KEY_KP8     : do['up'],
        libtcod.KEY_KP2     : do['down'],
        libtcod.KEY_KP4     : do['left'],
        libtcod.KEY_KP6     : do['right'],
        libtcod.KEY_KP7     : do['upleft'],
        libtcod.KEY_KP9     : do['upright'],
        libtcod.KEY_KP1     : do['downleft'],
        libtcod.KEY_KP3     : do['downright'],
        libtcod.KEY_KPDEC   : do['wait']
        }

# default map
smap = ['##############################################',
        '#######################      #################',
        '#####################    #     ###############',
        '######################  ###        ###########',
        '##################      #####             ####',
        '################       ########    ###### ####',
        '###############      #################### ####',
        '################    ######                  ##',
        '########   #######  ######   #     #     #  ##',
        '########   ######      ###                  ##',
        '########                                    ##',
        '####       ######      ###   #     #     #  ##',
        '#### ###   ########## ####                  ##',
        '#### ###   ##########   ###########=##########',
        '#### ##################   #####          #####',
        '#### ###             #### #####          #####',
        '####           #     ####                #####',
        '########       #     #### #####          #####',
        '########       #####      #########  #########',
        '#################### ##############  #########',
        '##################      #####             ####',
        '################       ########    ###### ####',
        '###############      #################### ####',
        '################    ######                  ##',
        '########   #######  ######   #######     #  ##',
        '########   ######      ###               #  ##',
        '########                     #######     #  ##',
        '####       ######      ###   #######     #  ##',
        '##########################   #######     #  ##',
        '##############################################',
        ]

#############################################
# drawing
#############################################

def draw():
	global fov_px, fov_py, fov_map, first
	global fov_init, fov_recompute, smap

	if first:
                first = False
                generateRandomMap()
		libtcod.console_clear(0)
		libtcod.console_set_foreground_color(0, libtcod.white)
		libtcod.console_put_char(0, fov_px+view_diff_width, fov_py, '@', libtcod.BKGND_NONE) # place player symbol
                updateUI('messages','I\'m Commander Shepard, and this is my favorite game on the Citadel.')

                # initialize player status window
                libtcod.console_set_foreground_color(0, libtcod.white)
                # player stats
                libtcod.console_print_left(0, 1, 1, libtcod.BKGND_NONE, p_name)
                libtcod.console_print_left(0, 1, 2, libtcod.BKGND_NONE, p_race)
                libtcod.console_print_left(0, 1, 3, libtcod.BKGND_NONE, 'Lvl    ' + str(p_lvl))
                libtcod.console_print_left(0, 1, 4, libtcod.BKGND_NONE, 'HP     ' + str(p_curr_hp) + ' / ' + str(p_max_hp))
                libtcod.console_print_left(0, 1, 5, libtcod.BKGND_NONE, 'Status ')
                libtcod.console_set_foreground_color(0, libtcod.green)
                libtcod.console_print_left(0, 8, 5, libtcod.BKGND_NONE, str(p_status))
                libtcod.console_set_foreground_color(0, libtcod.white)
                # player attributes
                libtcod.console_print_left(0, 1, 7, libtcod.BKGND_NONE, 'STR ' + str(p_curr_str) + ' (' + str(p_max_str) + ' - ' + str(p_debt_str) + ')')
                libtcod.console_print_left(0, 1, 8, libtcod.BKGND_NONE, 'DEX ' + str(p_curr_dex) + ' (' + str(p_max_dex) + ' - ' + str(p_debt_dex) + ')')
                libtcod.console_print_left(0, 1, 9, libtcod.BKGND_NONE, 'TEC ' + str(p_curr_tec) + ' (' + str(p_max_tec) + ' - ' + str(p_debt_tec) + ')')
                libtcod.console_print_left(0, 1, 10, libtcod.BKGND_NONE, 'KNL ' + str(p_curr_knl) + ' (' + str(p_max_knl) + ' - ' + str(p_debt_knl) + ')')

                # place window? get rid of this eventually
		for y in range(map_height):
		    for x in range(map_width):
                        #print 'x =',x,'and','y =',y
			if smap[y][x] == '=':
			    libtcod.console_put_char(0, x+view_diff_width, y, libtcod.CHAR_DHLINE, libtcod.BKGND_NONE)

	if not fov_init:
		fov_init = True
		fov_map = libtcod.map_new(map_width+view_diff_width, map_height)
		for y in range(map_height):
		    for x in range(map_width):
			if smap[y][x] == ' ':
			    libtcod.map_set_properties(fov_map, x+view_diff_width, y, True, True)
			elif smap[y][x] == '=':
			    libtcod.map_set_properties(fov_map, x+view_diff_width, y, True, False)

	if fov_recompute:
		fov_recompute = False
		libtcod.map_compute_fov(fov_map, fov_px+view_diff_width, fov_py, fov_radius, True)

	for y in range(map_height):
		for x in range(map_width):
                    affect, cell = 'dark', 'ground'
		    if libtcod.map_is_in_fov(fov_map, x+view_diff_width, y): affect = 'light'
		    if (smap[y][x] == '#'): cell = 'wall'
                    color = fov_colors['%s %s' % (affect, cell)]
                    libtcod.console_set_back(0, x+view_diff_width, y, color, libtcod.BKGND_SET)

#############################################
# game state update
#############################################

def keyActions(key):

    key = getKey(key)
    if key in movement_keys:
        updateUI('player position', key)
        updateUI('messages', 'You have moved ' + str(movement_keys[key]))
    elif key == 'e' :
        changeEnvironment('none')

#############################################
# initialization and main loop
#############################################

font = os.path.join('fonts', 'terminal10x10_gs_tc.png')
libtcod.console_set_custom_font(font, libtcod.FONT_LAYOUT_TCOD | libtcod.FONT_TYPE_GREYSCALE)

libtcod.console_init_root(window_width, window_height, 'The North Kingdom', False)

while not libtcod.console_is_window_closed():

    draw()
    libtcod.console_flush()
    key = libtcod.console_wait_for_keypress(True)
    keyActions(key)
    if key.vk == libtcod.KEY_ESCAPE:
        break
